package parabase

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"time"
	"wtester/config"
)

/**
  @author: weicai
  @since: 2024/5/7
  @desc: 参数
**/

type TaskParamKind string
type TaskParamScope string

const (
	TaskParamKindRandom TaskParamKind = "random" // 随机参数
	TaskParamKindRange  TaskParamKind = "range"  // 范围参数
)

const (
	TaskParamScopeGlobal TaskParamScope = "global" // stage 全局参数
	TaskParamScopeUser   TaskParamScope = "user"   // user 参数 or 线程参数
)

type TaskParamRely struct {
	Name  string `yaml:"name,omitempty"`  // 依赖的参数名称
	Start string `yaml:"start,omitempty"` // 依赖的参数开始值
	End   string `yaml:"end,omitempty"`   // 依赖的参数结束值
	Plus  bool   `yaml:"plus,omitempty"`  // 加或是减
}

type TaskParamInterface interface {
	Generator(*chan string)        // 生成器, 生成参数
	Random() string                // 随机生成参数
	GetKind() TaskParamKind        // 获取参数类型
	GetName() string               // 获取参数名称
	GetScope() TaskParamScope      // 获取参数作用域
	GetRely() *TaskParamRely       // 是否依赖参数
	RelyValue(value string) string // 依赖参数值

}

// TaskParamValues 提供固定的参数范围，直接使用固定的参数值
type TaskParamValues struct {
	Name   string         `yaml:"name,omitempty"`   // 参数名称
	Values []string       `yaml:"values,omitempty"` // 参数值
	Kind   TaskParamKind  `yaml:"kind,omitempty"`   // 参数类型: random, range
	Scope  TaskParamScope `yaml:"scope,omitempty"`  // 参数作用域
	Rely   *TaskParamRely `yaml:"rely,omitempty"`   // 依赖的参数
}

func (v *TaskParamValues) GetKind() TaskParamKind {
	return v.Kind
}

func (v *TaskParamValues) GetName() string {
	return v.Name
}

func (v *TaskParamValues) Generator(c *chan string) {
	for _, value := range v.Values {
		*c <- value
	}
}

func (v *TaskParamValues) GetScope() TaskParamScope {
	return v.Scope
}

func (v *TaskParamValues) Random() string {
	return v.Values[rand.Intn(len(v.Values))]
}

func (v *TaskParamValues) GetRely() *TaskParamRely {
	return v.Rely
}

func (v *TaskParamValues) RelyValue(value string) string {
	config.Logger.Warn("TaskParamValues 不支持依赖参数")
	return value
}

// TaskParamInteger 提供整数参数范围
type TaskParamInteger struct {
	Name  string         `yaml:"name,omitempty"`  // 参数名称
	Start int            `yaml:"start,omitempty"` // 参数开始值
	End   int            `yaml:"end,omitempty"`   // 参数结束值
	Step  int            `yaml:"step,omitempty"`  // 参数步长
	Kind  TaskParamKind  `yaml:"kind,omitempty"`  // 参数类型: random, range
	Scope TaskParamScope `yaml:"scope,omitempty"` // 参数作用域
	Rely  *TaskParamRely `yaml:"rely,omitempty"`  // 依赖的参数
}

func (v *TaskParamInteger) GetName() string {
	return v.Name
}

func (v *TaskParamInteger) GetKind() TaskParamKind {
	return v.Kind
}

func (v *TaskParamInteger) Generator(c *chan string) {
	for i := v.Start; i <= v.End; i += v.Step {
		*c <- strconv.Itoa(i)
	}
}

func (v *TaskParamInteger) Random() string {
	return strconv.Itoa(rand.Intn(v.End-v.Start) + v.Start)
}

func (v *TaskParamInteger) GetScope() TaskParamScope {
	return v.Scope
}

func (v *TaskParamInteger) GetRely() *TaskParamRely {
	return v.Rely
}

func (v *TaskParamInteger) RelyValue(value string) string {
	va, err := strconv.Atoi(value)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数值转换失败: %s", value))
		panic(err)
	}
	s, err := strconv.Atoi(v.Rely.Start)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数开始值转换失败: %s", v.Rely.Start))
		panic(err)
	}
	e, err := strconv.Atoi(v.Rely.End)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数结束值转换失败: %s", v.Rely.End))
		panic(err)
	}
	if v.Rely.Plus {
		return strconv.Itoa(va + rand.Intn(e-s) + s)
	}
	return strconv.Itoa(va - rand.Intn(e-s) + s)
}

// TaskParamDatetime 提供时间参数范围，允许设置时间的开始值、结束值、步长、单位（s、m、h、d）、格式
type TaskParamDatetime struct {
	Name   string         `yaml:"name,omitempty"`   // 参数名称
	Type   string         `yaml:"type,omitempty"`   // 参数类型
	Start  time.Time      `yaml:"start,omitempty"`  // 参数开始值
	End    time.Time      `yaml:"end,omitempty"`    // 参数结束值
	Step   time.Duration  `yaml:"step,omitempty"`   // 参数步长
	Unit   string         `yaml:"unit,omitempty"`   // 参数单位: s, m, h, d
	Format string         `yaml:"format,omitempty"` // 参数格式: 日期格式
	Kind   TaskParamKind  `yaml:"kind,omitempty"`   // 参数类型: random, range
	Scope  TaskParamScope `yaml:"scope,omitempty"`  // 参数作用域
	Rely   *TaskParamRely `yaml:"rely,omitempty"`   // 依赖的参数
}

func (v *TaskParamDatetime) GetName() string {
	return v.Name
}
func (v *TaskParamDatetime) GetKind() TaskParamKind {
	return v.Kind
}

func (v *TaskParamDatetime) Generator(c *chan string) {
	start, end := v.Start, v.End
	for start.Before(end) {
		*c <- start.Format(v.Format)
		start = start.Add(v.Step)
	}
}

func (v *TaskParamDatetime) GetScope() TaskParamScope {
	return v.Scope
}

func (v *TaskParamDatetime) Random() string {
	start, end := v.Start, v.End
	switch v.Unit {
	case "s":
		start2end := rand.Intn(int(end.Sub(start).Seconds()))
		return start.Add(time.Second * time.Duration(start2end)).Format(v.Format)
	case "m":
		start2end := rand.Intn(int(end.Sub(start).Minutes()))
		return start.Add(time.Minute * time.Duration(start2end)).Format(v.Format)
	case "h":
		start2end := rand.Intn(int(end.Sub(start).Hours()))
		return start.Add(time.Hour * time.Duration(start2end)).Format(v.Format)
	default:
		start2end := rand.Intn(int(end.Sub(start).Hours()) / 24)
		return start.Add(time.Hour * 24 * time.Duration(start2end)).Format(v.Format)
	}
}

func (v *TaskParamDatetime) GetRely() *TaskParamRely {
	return v.Rely
}

func (v *TaskParamDatetime) RelyValue(value string) string {
	va, err := time.Parse("2006-01-02 15:04:05", value)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数值转换失败: %s", value))
		panic(err)
	}
	s, err := strconv.Atoi(v.Rely.Start)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数开始值转换失败: %s", v.Rely.Start))
		panic(err)
	}
	e, err := strconv.Atoi(v.Rely.End)
	if err != nil {
		config.Logger.Error(fmt.Sprintf("TaskParamInteger 依赖参数结束值转换失败: %s", v.Rely.End))
		panic(err)
	}
	start2end := rand.Intn(e-s) + s
	if !v.Rely.Plus {
		start2end = -start2end
	}
	switch v.Unit {
	case "s":
		return va.Add(time.Second * time.Duration(start2end)).Format(v.Format)
	case "m":
		return va.Add(time.Minute * time.Duration(start2end)).Format(v.Format)
	case "h":
		return va.Add(time.Hour * time.Duration(start2end)).Format(v.Format)
	default:
		return va.Add(time.Hour * 24 * time.Duration(start2end)).Format(v.Format)
	}
}

func InitTaskParam(name, _type, kind, start, end, step string, values []string) (TaskParamInterface, error) {
	_kind := TaskParamKind(kind)
	switch _type {
	case "values":
		return &TaskParamValues{Name: name, Values: values, Kind: _kind}, nil
	case "int":
		_start, err := strconv.Atoi(start)
		if err != nil {
			return nil, err
		}
		_end, err := strconv.Atoi(end)
		if err != nil {
			return nil, err
		}
		_step, err := strconv.Atoi(step)
		if err != nil {
			return nil, err
		}
		return &TaskParamInteger{Name: name, Start: _start, End: _end, Step: _step, Kind: _kind}, nil
	case "datetime":
		_start, err := time.Parse("2006-01-02 15:04:05", start)
		if err != nil {
			return nil, err
		}
		_end, err := time.Parse("2006-01-02 15:04:05", end)
		if err != nil {
			return nil, err
		}
		lastIndex := strings.LastIndex(step, "")
		lastChar := step[lastIndex-1 : lastIndex]
		_step, err := time.ParseDuration(step)
		if err != nil {
			return nil, err
		}
		return &TaskParamDatetime{Name: name, Type: _type, Start: _start, End: _end, Step: _step, Unit: lastChar, Format: "2006-01-02 15:04:05", Kind: _kind}, nil
	default:
		return nil, fmt.Errorf("不支持的参数类型: %s", _type)
	}
}
